/*
 * Copyright (c) 2023-2025 110476592@qq.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file draw_panel.cpp
 * @brief 截图工具 
 * @author 110476592@qq.com 
 * @note   承接Qt项目外包定制开发。长期接收C++项目实训学徒,联系QQ：110476592。
 */

 
#include "draw_panel.h"
#include "draw_toolbar.h"
#include "tools/pen_picker.h"
#include "tools/shape_picker.h"
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include <QFileDialog>
#include <QPainter>
#include <QScreen>
#include <common/draw_context.h>
#include <common/global.h>

DrawPanel::DrawPanel(const QRect &rect, QWidget *parent) : QWidget(parent) {
  setWindowFlags(Qt::Widget | Qt::FramelessWindowHint // 去掉边框
                 | Qt::Tool                 // 任务栏不显示图标
                 | Qt::WindowSystemMenuHint // 隐藏系统菜单
                 | Qt::WindowStaysOnTopHint // 显示在最上层
  );
  // 禁止父窗口样式影响子控件样式
  setAttribute(Qt::WA_StyledBackground);
  setAttribute(Qt::WA_TranslucentBackground, true);

  m_pixmap = QPixmap(rect.width(), rect.height());
  m_pixmap.fill(QColor(255, 255, 255, 100));
  m_originPixmap = m_pixmap;

  setGeometry(rect);
  m_selection = rect; // 在画板模式下将选区设置和窗口一样大,载截屏里由选择确定

  setMouseTracking(
      true); // 设置窗体追踪鼠标,窗体默认设置为不追踪。
             // 默认情况，只有鼠标按键按下后
             // 鼠标移动时mousePressEvent才会被调用。
             // 但是如果mousetraking设置为true，只需要移动鼠标就会调用
  // 将字体库加入QT
  el::ELIconUtil::load("://res/font/www.iconfont.cn.ttf");
  m_workMode = WorkMode::AREA_DRAW;
  DrawContext::setPainterType(PainterType::PENCIL);
}

DrawPanel::~DrawPanel() {}

QRect DrawPanel::toDevicePixelSelection() {
  if (m_selection.isNull()) {
    return QRect();
  }

  auto devicePixelRatio = m_pixmap.devicePixelRatio();

  return QRect(m_selection.left() * devicePixelRatio,
               m_selection.top() * devicePixelRatio,
               m_selection.width() * devicePixelRatio,
               m_selection.height() * devicePixelRatio);
}

QPixmap DrawPanel::getSelectedPixmap() {
  if (m_selection.isNull()) { // copy full screen when no selection
    return m_pixmap;
  } else {
    return m_pixmap.copy(toDevicePixelSelection());
  }
}

void DrawPanel::saveSelectedPixmap() {
  QString fileName = QFileDialog::getSaveFileName(
      this, "图片另存为", "", "Images (*.png *.xpm *.jpg *.bmp)");
  if (fileName.isEmpty()) {
    return;
  }
  getSelectedPixmap().save(fileName);
}

void DrawPanel::paintEvent(QPaintEvent *event) {
  Q_UNUSED(event); // 消除未用的参数的编译警告
  // 将桌面的图像绘制到桌面上。
  QPainter painter(this);
  painter.drawPixmap(0, 0, m_pixmap);
}

void DrawPanel::updateDrawCursor() { setCursor(Qt::ArrowCursor); }

void DrawPanel::createToolBar() {
  m_floatToolBar = new DrawToolBar(this);
  m_floatToolBar->setVisible(true);
}



bool DrawPanel::handleCustomeCommand(ToolButtonEx *btn)
{
  switch (btn->commandType()) {
  case CommandType::CMD_MOVE_TOOL_BAR:{
    return true;
  }
  default:
    break;
  }
  return false;
}


void DrawPanel::handleCommand(ToolButtonEx *btn) {
  if (handleCustomeCommand(btn)) {
    return;
  }


  switch (btn->commandType()) {
  case CommandType::CMD_CLIPBOARD: {
      QClipboard *clipboard = QApplication::clipboard();
      clipboard->setPixmap(getSelectedPixmap());
    break;
  }
  case CommandType::CMD_PEN: {
    PenPicker &picker = PenPicker::showPicker(btn);
    connect(&picker,&PenPicker::penSelected,[this](){
        // 为了简化使用，选择了颜色和画笔，如果没有设置图形，就自动设置为自由绘
        m_workMode = WorkMode::AREA_DRAW; //为了兼容截屏模式，这里要再写一
        if(DrawContext::painterType() == PainterType::NA){
            DrawContext::setPainterType(PainterType::PENCIL);
        }
    });


    break;
  }
  case CommandType::CMD_SAVE: {
    saveSelectedPixmap();
    break;
  }
  case CommandType::CMD_SHAP: {
    ShapePicker &picker = ShapePicker::showPicker(btn);
    connect(&picker,&ShapePicker::shapeSelected,[this](PainterType ainterType){
        m_workMode = WorkMode::AREA_DRAW; //为了兼容截屏模式，这里要再写一
        DrawContext::setPainterType(ainterType);
    });
    break;
  }
  case CommandType::CMD_UNDO: {
    undo();
    break;
  }

  case CommandType::CMD_REDO: {
    redo();
    break;
  }

  case CommandType::CMD_CLEAN: {
    clean();
    break;
  }

  case CommandType::CMD_MOVE_TOOL_BAR: {
    break;
  }

  default:
    break;
  }
}

void DrawPanel::init() {
  createToolBar();

  m_floatToolBar->initButtons();

  connect(m_floatToolBar, &AbsFloatToolBar::onClicked, this,
          [=](ToolButtonEx *btn) { handleCommand(btn); });
  updateToolBarPosition();
}

void DrawPanel::updateToolBarPosition() {
  m_floatToolBar->enableButton(CommandType::CMD_UNDO,false);
  m_floatToolBar->enableButton(CommandType::CMD_REDO,false);
  m_floatToolBar->enableButton(CommandType::CMD_CLEAN,false);
  m_floatToolBar->enableButton(CommandType::CMD_SAVE,false);
  m_floatToolBar->enableButton(CommandType::CMD_CLIPBOARD,false);

  QRect rc = m_selection.normalized();

  if (rc.isNull()) {
    return;
  }

  m_floatToolBar->updatePosition(rect(), rc);
  m_floatToolBar->setVisible(true);
}

void DrawPanel::mousePressEvent(QMouseEvent *event) {
  if (event->button() == Qt::LeftButton) {
    m_leftPressed = true;
    // 如果是绘图模式就记录经过的点,只能在选区里绘制，兼容截屏模式
    if ((m_workMode == WorkMode::AREA_DRAW) && m_selection.contains(event->pos())) {
      m_drawRecords.emplace_back(event->pos());
      m_floatToolBar->enableButton(CommandType::CMD_UNDO,true);
      m_floatToolBar->enableButton(CommandType::CMD_CLEAN,true);
      m_floatToolBar->enableButton(CommandType::CMD_SAVE,true);
      m_floatToolBar->enableButton(CommandType::CMD_CLIPBOARD,true);

    }
    return;
  }
}

void DrawPanel::mouseMoveEvent(QMouseEvent *event) {
  //只能在选区里绘制，兼容截屏模式
  if (m_leftPressed && (m_workMode == WorkMode::AREA_DRAW) &&  m_selection.contains(event->pos())) {
    m_drawRecords.back().addPoint(event->pos());
    drawAll();
    update();
  }
}

void DrawPanel::mouseReleaseEvent(QMouseEvent *event) {
  Q_UNUSED(event); // 消除未用的参数的编译警告
  m_leftPressed = false;
  // 绘图模式下,只能在选区里绘制，兼容截屏模式
  if ((m_workMode == WorkMode::AREA_DRAW) &&  m_selection.contains(event->pos())) {
    drawOne(m_drawRecords.back());
    update();
  }
}

void DrawPanel::drawAll() {
   m_pixmap = m_originPixmap;//重置画布，重绘所有

  for (DrawRecord &item : m_drawRecords) {
    drawOne(item);
  }
  update();
}

void DrawPanel::drawOne(DrawRecord &item) {
  QPainter painter(&m_pixmap);
  painter.setRenderHint(QPainter::Antialiasing);
  item.draw(painter);
}

void DrawPanel::keyPressEvent(QKeyEvent *e) {
  if (e->key() == Qt::Key_Escape) {
    close();
  }
  QWidget::keyPressEvent(e);
}


void DrawPanel::undo() {
  if (!m_drawRecords.empty()) {
    m_undoRecords.push_back(m_drawRecords.back());

    m_drawRecords.pop_back();

    drawAll();
    m_floatToolBar->enableButton(CommandType::CMD_REDO,true);
    m_floatToolBar->enableButton(CommandType::CMD_UNDO,!m_drawRecords.empty());
    m_floatToolBar->enableButton(CommandType::CMD_SAVE,!m_drawRecords.empty());
    m_floatToolBar->enableButton(CommandType::CMD_CLIPBOARD,!m_drawRecords.empty());
  }else{
    m_floatToolBar->enableButton(CommandType::CMD_UNDO,false);

  }
}

void DrawPanel::redo() {
  if (!m_undoRecords.empty()) {
    m_drawRecords.push_back(m_undoRecords.back());
    m_undoRecords.pop_back();
    m_floatToolBar->enableButton(CommandType::CMD_UNDO,true);
    m_floatToolBar->enableButton(CommandType::CMD_REDO,!m_undoRecords.empty());
    drawAll();
  }else{
    m_floatToolBar->enableButton(CommandType::CMD_REDO,false);
  }
}

void DrawPanel::clean() {
  m_drawRecords.clear();
  m_undoRecords.clear();
  m_floatToolBar->enableButton(CommandType::CMD_UNDO,false);
  m_floatToolBar->enableButton(CommandType::CMD_REDO,false);
  m_floatToolBar->enableButton(CommandType::CMD_CLEAN,false);
  m_floatToolBar->enableButton(CommandType::CMD_SAVE,false);
  m_floatToolBar->enableButton(CommandType::CMD_CLIPBOARD,false);

  drawAll();
}
